﻿using System;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;

namespace Sustainalytics.ClientDW.DataAccessLayer
{
    public static class PropertyNameExtensions
    {
        /// <summary>
        /// Extension method for exposing the name of properties.
        /// Use: objectReference.PropertyName( x => x.property ) to retrieve the name.
        /// </summary>
        /// <returns>
        /// Property name of the property expression provided.
        /// </returns>
        public static string PropertyName<T, TReturn>(this T obj, Expression<Func<T, TReturn>> property) where T : class
        {
            var body = (MemberExpression)property.Body;
            if (body == null)
                throw new ArgumentException("The provided expression did not point to a property.");

            return body.Member.Name;
        }

        public static string GetPropertyName<TPropertySource>(Expression<Func<TPropertySource, object>> expression)
        {
            var lambda = expression as LambdaExpression;

            MemberExpression memberExpression;

            if (lambda.Body is UnaryExpression)
            {
                var unaryExpression = lambda.Body as UnaryExpression;

                memberExpression = unaryExpression.Operand as MemberExpression;
            }
            else
            {
                memberExpression = lambda.Body as MemberExpression;
            }

            Debug.Assert(memberExpression != null, "Please provide a lambda expression like 'n => n.PropertyName'");

            var propertyInfo = memberExpression.Member as PropertyInfo;

            return propertyInfo != null ? propertyInfo.Name : null;
        }

        public static string GetPropertyName<T>(Expression<Func<T>> propertyLambda)
        {
            var me = propertyLambda.Body as MemberExpression;

            if (me == null)
            {
                throw new ArgumentException("You must pass a lambda of the form: '() => Class.Property' or '() => object.Property'");
            }

            var propertyInfo = me.Member as PropertyInfo;

            return propertyInfo != null ? propertyInfo.Name : null;
        }
    }
}
